package v2

import (
	rpcv1 "gluenet/internal/agent/api/rpc/v1"
	metav1 "gluenet/pkg/agent/option"
	corev1 "gluenet/pkg/agent/types"
	"gluenet/pkg/agent/v2/rpc"
)

type ContainerGetter interface {
	Containers(guid string) ContainerInterface
}

type ContainerInterface interface {

	// ask an agent to create a container
	//
	// Example:
	// 	container := corev1.Container{
	// 		Name: `test-disturb-container`,
	// 		Config: &docker.Config{
	// 			Image: `39.101.140.145:5000/cpu-ctrl-core-1:latest`,
	// 			Cmd:   []string{`/bin/sh`, `/root/boot.sh`},
	// 		},
	// 		HostConfig: &docker.HostConfig{},
	// 	}
	// 	rlt, err := cli.Containers(UserContainerApp).Create(&container, metav1.CreateOptions{})
	Create(container *corev1.Container, opt metav1.CreateOptions) (*corev1.DockerContainerDetailObj, error)

	// ask an agent to delete a container
	//
	// Example:
	// 	err := cli.Containers(UserContainerApp).Delete(metav1.DeleteOptions{})
	Delete(opt metav1.DeleteOptions) error

	// ask an agent to get a container's detail info
	//
	// Example:
	//	rlt, err := cli.Containers(UserContainerApp).Get(metav1.GetOptions{})
	Get(opt metav1.GetOptions) (*corev1.DockerContainerDetailObj, error)

	// ask an agent to update a container's resource
	//
	// Example:
	// 	rlt, err := cli.Containers(UserContainerApp).Update(corev1.ContainerOptions{CpusetCpus: `2`})
	Update(opt metav1.ContainerOptions) (*corev1.DockerContainerDetailObj, error)
}

type containers struct {
	client rpc.Interface
	guid   string
}

func newContainers(c *CoreClient, guid string) *containers {
	return &containers{
		client: c.RPCClient(),
		guid:   guid,
	}
}

func (c *containers) Create(container *corev1.Container, opt metav1.CreateOptions) (result *corev1.DockerContainerDetailObj, err error) {
	result = &corev1.DockerContainerDetailObj{}
	err = c.client.Invoke().
		Api(rpcv1.CreateContainer).
		Guid(c.guid).
		Resource(rpcv1.CONTAINER_RESOURCE).
		Spec(*container).
		Do().
		Into(result)
	return
}

func (c *containers) Delete(opt metav1.DeleteOptions) error {
	return c.client.Invoke().
		Api(rpcv1.DeleteContainer).
		Guid(c.guid).
		Resource(rpcv1.CONTAINER_RESOURCE).
		Do().
		Error()
}

func (c *containers) Get(opt metav1.GetOptions) (result *corev1.DockerContainerDetailObj, err error) {
	result = &corev1.DockerContainerDetailObj{}
	err = c.client.Invoke().
		Api(rpcv1.GetContainer).
		Guid(c.guid).
		Resource(rpcv1.CONTAINER_RESOURCE).
		Do().
		Into(result)
	return
}

func (c *containers) Update(opt metav1.ContainerOptions) (result *corev1.DockerContainerDetailObj, err error) {
	result = &corev1.DockerContainerDetailObj{}

	err = c.client.Invoke().
		Api(rpcv1.UpdateContainer).
		Guid(c.guid).
		Resource(rpcv1.CONTAINER_RESOURCE).
		Options(&opt).
		Do().
		Into(result)
	return
}
